#!/user/bin/env python
# coding:utf-8
"""
Author myYouTh
Date:2020/2/14 001416:11
Desc: 一百道python练习题
"""


import logging
import sys

# 默认输出到控制台的日志级别是warning, 使用函数进行日志信息的配置
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(name)s %(levelname)s %(message)s",
                    datefmt='%Y-%m-%d  %H:%M:%S %a')
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(name)s %(levelname)s %(message)s",
                    datefmt='%Y-%m-%d  %H:%M:%S %a')
logging.basicConfig(level=logging.ERROR, format="%(asctime)s %(name)s %(levelname)s %(message)s",
                    datefmt='%Y-%m-%d  %H:%M:%S %a')
logging.basicConfig(level=logging.FATAL, format="%(asctime)s %(name)s %(levelname)s %(message)s",
                    datefmt='%Y-%m-%d  %H:%M:%S %a')
# 跟日志记录器
global_logger = logging.getLogger()


def one(data: list, length: int):
    """
    给定一组数字，能组成不重复的数字且位数是length的数字
    :param data: 一组数字
    :param length: 组成数字的位数
    :return: 所有组合的列表
    """
    # 存放不重复数字的列表
    not_repetition: list = []
    length_list: list = []
    if not len(data) or not length:
        raise ValueError('列表或位数不能为空')
    else:
        for i in range(length):
            length_list.append("a"+str(i))
    if len(data) < length:
        raise NameError("位数不能超过列表大小")
        # lis1.append(locals()[i])

    # 拼接可执行的python语句,表示生成式中的变量值
    str1 = ','.join(length_list)
    # 拼接可执行的python语句,表示生成式中的for循环数量
    str2 = (f' for a in {data}' * length)
    # 构造生成式表达式中for循环的变量
    str3 = str2.split(' ')
    length_list1 = list(reversed(length_list))
    for index, i in enumerate(str3):
        if i == 'a':
            # pop方法从最后一个位置取元素，
            str3[index] = length_list1.pop()
    str2 = ' '.join(str3)
    # 拼接后的字符串，包含一个列表生成式的字符串
    # 构造生成式表达式，去掉引号就是执行字符串里面的python表达式
    str9 = eval('(' + '(' + str1 + ')' + str2 + ')')

    # 去掉重复的数字
    for index, i in enumerate(str9):
        if len(set(i)) == length:
            number = ''.join([str(j) for j in i])
            not_repetition.append(int(number))
    return not_repetition


class DataDescriptor(object):
    """数据描述符"""
    def __get__(self, instance, owner):
        """
        返回数据描述符的值
        :param instance:
        :param owner:
        :return:
        """
        return self.value

    def __delete__(self, instance):
        pass


class ListDataDescriptor(DataDescriptor):
    """参数类型检查，判断参数是否是list"""
    def __set__(self, instance, value):
        if not isinstance(value, list):
            raise NameError(f"初始化方法的参数类型必须是list")
        self.value = value


class IntDataDescriptor(DataDescriptor):
    """参数类型检查，判断参数是否是int"""
    def __set__(self, instance, value):
        if not isinstance(value, int):
            raise NameError(f"初始化方法的参数类型必须是int")
        self.value = value


class One(object):
    data = ListDataDescriptor()
    length = IntDataDescriptor()
    """给定一组数字，能组成不重复的数字且位数是length的数字"""
    def __init__(self, data, length):
        # 使用数据描述符做参数类型检查时，实例变量不能是私有的、也不能是受保护的，不然不会进入到数据描述符类中做类型检查
        self.data = data
        self.length = length
        # 存放不重复数字的列表
        self._not_repetition: list = []
        # 存放列表生成式的变量名
        self._length_list: list = []

        if not self.length:
            raise NameError('位数不能为空')
        else:
            for i in range(self.length):
                self._length_list.append("a" + str(i))
        if len(self.data) < self.length:
            raise NameError("位数不能超过列表大小")

    def join_length_list(self) -> str:
        """构造列表生成式的变量名"""
        return ','.join(self._length_list)

    def join_for(self) -> str:
        """构造列表生成式中for循环的数量"""
        return f' for a in {self.data}' * self.length

    def construction_listgeneration(self) -> str:
        """构造列表生成式"""
        str1 = self.join_length_list()
        str2 = self.join_for()
        str3 = str2.split(' ')
        length_list1 = list(reversed(self._length_list))
        for index, i in enumerate(str3):
            if i == 'a':
                # pop方法从最后一个位置取元素，
                str3[index] = length_list1.pop()
        str2 = ' '.join(str3)
        # 列表生成式包含在一串字符串中
        return '(' + '(' + str1 + ')' + str2 + ')'

    def not_repetition(self) -> list:
        """打印所有组合且不重复的数字的列表"""
        str9 = eval(self.construction_listgeneration())
        for index, i in enumerate(str9):
            if len(set(i)) == self.length:
                number = ''.join([str(j) for j in i])
                self._not_repetition.append(int(number))
        return self._not_repetition

    def __str__(self):
        return f"所有数字组合的情况共{len(list(eval(self.construction_listgeneration())))}, 其中不重复数字的组合有" \
            f"{len(self._not_repetition)}"


def func_logging(func_name) ->object:
    """
    将日志记录器实例logger添加到函数作用域中,每个函数都有自己的日志记录器
    函数装饰器，向函数的作用域中加入logger实例，便于每个函数都可以有自己的日志记录器
    """
    func_name.__dict__['logger'] = logging.getLogger(__file__ + ' ' + func_name.__qualname__)
    return func_name


@func_logging
def right_move(data: list, right_move_num: int) -> list:
    """
    列表右移
    :param data:
    :param right_move_num:
    :return:
    """
    # 获取logger实例
    current_function_name = sys._getframe().f_code.co_name
    logger_object = globals()[current_function_name]
    logger = logger_object.__dict__.get('logger', None)

    try:
        logger.debug(f"成功进入{current_function_name}函数")
        after_list = data[-right_move_num:]
        after_list = after_list[:]
        after_list.extend(data[0:-right_move_num])
        logger.debug(f"result:{after_list}")
        return after_list
    except Exception:
        global_logger.fatal(f"函数{current_function_name}函数未做处理")


def left_move(data: list, left_move_num: int) -> list:
    """
    列表左移
    :param data:
    :param left_move_num:
    :return:
    """
    after_list = data[:left_move_num]
    result = data[left_move_num:] + after_list[:]
    return result


@func_logging
def rotate(data: list, move_num: int) -> list:
    """列表移动"""
    # 在函数内部获取当前运行函数的函数名。类中的方法也是此方法
    # print(sys._getframe().f_code.co_name)

    # 获取logger实例
    current_function_name = sys._getframe().f_code.co_name
    logger_object = globals()[current_function_name]
    logger = logger_object.__dict__.get('logger', None)

    try:
        # 设置日志输出格式
        logger.debug(f"成功进入{current_function_name}函数, 数据参数data:{data}, 位移参数move_num:{move_num}")
        if move_num > 0:
            # 右移
            logger.debug(f"列表右移")
            if move_num >= len(data):
                new_right_move_num = move_num % len(data)
                logger.debug(f"位移长度{move_num}大于列表长度{len(data)},取余计算应右移{new_right_move_num}位")
                result = right_move(data, new_right_move_num)
                logger.debug(f"列表右移结果:{result}")
                return result
            elif move_num < len(data):
                logger.debug(f"位移长度{move_num}小于列表长度{len(data)},取余计算应右移{move_num}位")
                result = right_move(data, move_num)
                logger.debug(f"列表右移结果:{result}")
                return result
        elif move_num < 0:
            # 左移
            logger.debug(f"列表左移")
            if abs(move_num) >= len(data):
                new_left_move_num = abs(move_num) % len(data)
                logger.debug(f"位移长度{move_num}大于列表长度{len(data)},取余计算应左移{new_left_move_num}位")
                result = left_move(data, new_left_move_num)
                logger.debug(f"列表左移结果:{result}")
                return result
            elif abs(move_num) < len(data):
                move_num = abs(move_num)
                logger.debug(f"位移长度{move_num}小于列表长度{len(data)},取余计算应左移{move_num}位")
                result = left_move(data, move_num)
                logger.debug(f"列表左移结果:{result}")
                return result
        else:
            logger.debug(f"位移长度零，不位移")
            return data
    except Exception:
        global_logger.fatal(f"{current_function_name}函数未做处理")


if __name__ == '__main__':
    # print(one([1, 2, 3, 4], 3))
    # 第一题
    # one = One([1,4,2,3], 2)
    # print(one.not_repetition())
    li = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    a = rotate(li, 23)
    print(a)
    #print(globals())



